package com.demo11;

import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Emulator;
import com.github.unidbg.Module;
import com.github.unidbg.arm.backend.Unicorn2Factory;
import com.github.unidbg.arm.context.RegisterContext;
import com.github.unidbg.debugger.BreakPointCallback;
import com.github.unidbg.file.FileResult;
import com.github.unidbg.file.IOResolver;
import com.github.unidbg.file.linux.AndroidFileIO;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.*;
import com.github.unidbg.linux.android.dvm.api.Binder;
import com.github.unidbg.linux.android.dvm.api.SystemService;
import com.github.unidbg.linux.android.dvm.array.ByteArray;
import com.github.unidbg.linux.file.ByteArrayFileIO;
import com.github.unidbg.linux.file.SimpleFileIO;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.pointer.UnidbgPointer;
import com.github.unidbg.spi.SyscallHandler;
import com.github.unidbg.virtualmodule.android.AndroidModule;
import com.github.unidbg.virtualmodule.android.JniGraphics;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

public class DidiWsg extends AbstractJni implements IOResolver {
    private final AndroidEmulator emulator;
    private final VM vm;
    private final Module module;
    private final DvmClass SecurityLib;

    DidiWsg() {

        // 创建模拟器实例
        emulator = AndroidEmulatorBuilder
                .for32Bit()
                .addBackendFactory(new Unicorn2Factory(true))
                .setRootDir(new File("target/rootfs"))
                .build();

        // 开启多线程
        emulator.getBackend().registerEmuCountHook(100000); // 设置执行多少条指令切换一次线程
        emulator.getSyscallHandler().setEnableThreadDispatcher(true);
        // 模拟器的内存操作接口
        final Memory memory = emulator.getMemory();
        // 设置系统类库解析
        memory.setLibraryResolver(new AndroidResolver(23));
        // 创建Android虚拟机
        vm = emulator.createDalvikVM(new File("unidbg-android/src/test/resources/demo11/apkfiles/chengxin.apk"));

        new JniGraphics(emulator, vm).register(memory);
        new AndroidModule(emulator, vm).register(memory);

        vm.setJni(this);
        vm.setVerbose(true);

        emulator.getSyscallHandler().addIOResolver(this);
        DalvikModule dm = vm.loadLibrary("didiwsg", true);
        module = dm.getModule();
        dm.callJNI_OnLoad(emulator);
        SecurityLib = vm.resolveClass("com/didi/security/wireless/SecurityLib");
    }

    @Override
    public FileResult resolve(Emulator emulator, String pathname, int oflags) {
        System.out.println("file open:"+pathname);
        if(pathname.equals("/proc/self/maps")){
            return FileResult.success(new SimpleFileIO(oflags, new File("unidbg-android/src/test/resources/demo11/files/maps"), pathname));
        }
        if(pathname.equals("/data/app/com.wujie.chengxin-f18rNQm4nrkqUntzsQ_fnA==/base.apk")){
            return FileResult.success(new SimpleFileIO(oflags, new File("unidbg-android/src/test/resources/demo11/apkfiles/chengxin.apk"), pathname));
        }
        if(pathname.equals("/proc/self/status")) {
            return FileResult.success(new ByteArrayFileIO(oflags, pathname, ("TracerPid: 0").getBytes()));
        }
        return null;
    }

    public static void main(String[] args) {
        DidiWsg didiWsg = new DidiWsg();
        didiWsg.callinit();
        didiWsg.callSig();
    }

    @Override
    public DvmObject<?> callStaticObjectMethod(BaseVM vm, DvmClass dvmClass, String signature, VarArg varArg) {
        switch (signature){
            case "com/didi/security/wireless/SecurityLib->getSensorListener()Landroid/hardware/SensorEventListener;":{
                return vm.resolveClass("android/hardware/SensorEventListener").newObject(signature);
            }
            case "com/didi/security/wireless/SecurityLib->getFeature(I)Ljava/lang/Object;": {
                int index = varArg.getIntArg(0);
//                System.out.println("lilac call feature:"+index);
                switch (index){
                    case 8197:{
                        return new StringObject(vm, "com.wujie.chengxin");
                    }
                    case 8198:{
                        return new StringObject(vm, "3.0.1");
                    }
                }
            }
            case "java/lang/System->getProperty(Ljava/lang/String;)Ljava/lang/String;":{
                return null;
            }
            case "android/os/ServiceManager->getService(Ljava/lang/String;)Landroid/os/IBinder;":{
                return new Binder(vm, signature);
            }
            case "android/os/Environment->getExternalStorageDirectory()Ljava/io/File;":{
                return vm.resolveClass("java/io/File").newObject("/storage/emulated/0");
            }
            case "java/util/Locale->getDefault()Ljava/util/Locale;":
                return dvmClass.newObject(Locale.getDefault());
        }
        return super.callStaticObjectMethod(vm, dvmClass, signature, varArg);
    }

    // 运行耗时较长，原因未知。
    public void callinit(){
        DvmObject<?> context = vm.resolveClass("com/wujie/chengxin/CxShadowApplication", vm.resolveClass("android/content/Context")).newObject(null); // context
        SecurityLib.newObject(null).callJniMethodInt(emulator, "nativeInit(Landroid/content/Context;)I", context);
    }

    public void callSig(){
        List<Object> list = new ArrayList<>(10);
        list.add(vm.getJNIEnv()); // 第一个参数是env

        list.add(0x100);
        DvmObject<?> context = vm.resolveClass("com/wujie/chengxin/CxShadowApplication", vm.resolveClass("android/content/Context")).newObject(null); // context
        list.add(vm.addLocalObject(context));
        list.add(1637131205452L);
        StringObject phone = new StringObject(vm, "18796253051");
        list.add(vm.addLocalObject(phone));
        ByteArray bytearr = new ByteArray(vm, ("lid1158706c643d7074253235334431363337313331313939333636253235323661696425323533443131353825323532366569642532353344637879785f6d6f6e69746f725f6b65795f6576656e742532353236742532353344312532353236617474727325323533442532353235374225323532353232777853444b56657273696f6e253235323532322532353235334125323532353232312e382e30253235323532322532353235324325323532353232706c6174666f726d25323532353232253235323533412532353353232616e64726f696425323532353232253235323532432532353235323273637265656e4865696768742532353235323225323532353341373835253235323532432532353235323273637265656e576964746825323532353232253235323533413339332533532353243253235323532326d616e7566616374757265722532353235323225323532353341253235323532325869616f6d692532353235323225323532353243253235323532326d6f64656c2532353235323225323532353341253235323532324d49582532332353230325325323532353232253235323532432532353235323273797374656d2532353235323225323532353341253235323532323130253235323532322532353235324325323532353232777856657273696f6e25323532353232253235323533412532353353232332e302e312532353235323225323532353243253235323532326275696c64506b6754696d652532353235323225323532353341253235323532323230323131313132323032312532353235323225323532353243253235323532326275696c64506b67461746525323532353232253235323533412532353235323231322532353235323225323532353243253235323532326d696e69417070456e7625323532353232253235323533412532353235323272656c65617365253235323532322532353235324325323532332326d696e6941707056657273696f6e253235323532322532353235334125323532353232332e32342e302532353235323225323532353243253235323532326369747969642532353235323225323532353341313725323532353243253235323532326f7a253353235323225323532353341393939393939253235323532432532353235323273636f7065253235323532322532353235334125323532353232646f6d61696e5f6d61696e50726f636573732532353235323225323532353243253235323532326b6579253235335323225323532353341253235323532326c6f67696e5f73686f704c6f67696e5f746f74616c5f636f756e7425323532353232253235323537442532353236736964253235334431333231396461342d666238612d343165622d613939662d643664616332333466235302532353236762532353344312e302e3025323" +
                "532367369253235334432302532353236626964253235334432323435373534313734353935").getBytes(StandardCharsets.UTF_8));
        list.add(vm.addLocalObject(bytearr));
        Number numbers = module.callFunction(emulator, 0xa5a5, list.toArray());
        DvmObject<?> dvmObject = vm.getObject(numbers.intValue());
        String ret = dvmObject.getValue().toString();
        System.out.println("nativeSig:"+ret);
    }


    @Override
    public DvmObject<?> callObjectMethod(BaseVM vm, DvmObject<?> dvmObject, String signature, VarArg varArg) {
        switch (signature){
            case "android/content/Context->getSharedPreferences(Ljava/lang/String;I)Landroid/content/SharedPreferences;":{
                String tableName = (String) varArg.getObjectArg(0).getValue();
                int arg2 = varArg.getIntArg(1);
                return vm.resolveClass("android/content/SharedPreferences").newObject(tableName);
            }
            case "android/content/SharedPreferences->getString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;":{
//                System.out.println("lilac call getString");
                return new StringObject(vm, "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");
            }
            case "android/content/Context->getPackageCodePath()Ljava/lang/String;":
                return new StringObject(vm, "/data/app/com.wujie.chengxin-f18rNQm4nrkqUntzsQ_fnA==/base.apk");
            case "android/content/Context->getFilesDir()Ljava/io/File;":
                return vm.resolveClass("java/io/File").newObject(signature);
                ///data/data/com.wujie.chengxin/files
            case "java/io/File->getCanonicalPath()Ljava/lang/String;":
                return new StringObject(vm, "/data/data/com.wujie.chengxin/files");
            case "android/content/Context->getSystemService(Ljava/lang/String;)Ljava/lang/Object;":{
                StringObject serviceName = varArg.getObjectArg(0);
                assert serviceName != null;
                return new SystemService(vm, serviceName.getValue());
            }
            case "android/view/WindowManager->getDefaultDisplay()Landroid/view/Display;":{
                return vm.resolveClass("android/view/Display").newObject(null);
            }
            case "java/util/Locale->getLanguage()Ljava/lang/String;":
                Locale locale = (Locale) dvmObject.getValue();
                return new StringObject(vm, locale.getLanguage());
        }
        return super.callObjectMethod(vm, dvmObject, signature, varArg);
    }

    @Override
    public DvmObject<?> newObject(BaseVM vm, DvmClass dvmClass, String signature, VarArg varArg) {
        switch (signature){
            case "android/util/DisplayMetrics-><init>()V":{
                return dvmClass.newObject(null);
            }
        }
        return super.newObject(vm, dvmClass, signature, varArg);
    }

    @Override
    public void callVoidMethod(BaseVM vm, DvmObject<?> dvmObject, String signature, VarArg varArg) {
        switch (signature){
            case "android/view/Display->getRealMetrics(Landroid/util/DisplayMetrics;)V":{
                return;
            }
        }
        super.callVoidMethod(vm, dvmObject, signature, varArg);
    }

    @Override
    public int getIntField(BaseVM vm, DvmObject<?> dvmObject, String signature) {
        switch (signature){
            case "android/util/DisplayMetrics->widthPixels:I":{
                return 1080;
            }
            case "android/util/DisplayMetrics->heightPixels:I":{
                return 2160;
            }
        }
        return super.getIntField(vm, dvmObject, signature);
    }
}
